package org.csu.tank.server;

import javafx.application.Application;
import javafx.stage.Stage;
import org.csu.tank.client.TankClient;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.*;
import java.util.ArrayList;
import java.util.List;

public class TankServer extends Application {


      public static int ID = 100;//id号的初始序列
      public static final int TCP_PORT = 55555;//TCP端口号
      public static final int UDP_PORT = 55556;//转发客户端数据的UDP端口号
      public static final int TANK_DEAD_UDP_PORT = 55557;//接收客户端坦克死亡的端口号
      private List<Client> clients = new ArrayList<>();//客户端集合
      private static final int SERVER_HEIGHT = 500;
      private static final int SERVER_WIDTH = 300;


      public static void main(String[] args) {
            TankServer ts = new TankServer();
            ts.startServer();
            launch(args);
      }

      @Override
      public void start(Stage primaryStage) {

      }

      public void startServer(){
            new Thread(new UDPThread()).start();
            new Thread(new TankDeadUDPThread()).start();
            ServerSocket ss = null;
            try {
                  ss = new ServerSocket(TCP_PORT);//在TCP欢迎套接字上监听客户端连接
                  System.out.println("TankServer has started...");
            } catch (IOException e) {
                  e.printStackTrace();
            }

            while(true){
                  Socket s = null;
                  try {
                        s = ss.accept();//给客户但分配专属TCP套接字
                        System.out.println("A client has connected...");
                        DataInputStream dis = new DataInputStream(s.getInputStream());
                        int UDP_PORT = dis.readInt();//记录客户端UDP端口
                        Client client = new Client(s.getInetAddress().getHostAddress(), UDP_PORT, ID);//创建Client对象
                        clients.add(client);//添加进客户端容器

                        DataOutputStream dos = new DataOutputStream(s.getOutputStream());
                        dos.writeInt(ID++);//向客户端分配id号
                        dos.writeInt(TankServer.UDP_PORT);//告诉客户端自己的UDP端口号
                        dos.writeInt(TankServer.TANK_DEAD_UDP_PORT);
                  }catch (IOException e) {
                        e.printStackTrace();
                  }finally {
                        try {
                              if(s != null) s.close();
                        } catch (IOException e) {
                              e.printStackTrace();
                        }
                  }
            }
      }

      private class UDPThread implements Runnable{

            byte[] buf = new byte[1024];

            @Override
            public void run() {
                  DatagramSocket ds = null;
                  try{
                        ds = new DatagramSocket(UDP_PORT);
                  }catch (SocketException e) {
                        e.printStackTrace();
                  }

                  while (null != ds){
                        DatagramPacket dp = new DatagramPacket(buf, buf.length);
                        try {
                              ds.receive(dp);
                              for (Client c : clients){
                                    dp.setSocketAddress(new InetSocketAddress(c.IP, c.UDP_PORT));
                                    ds.send(dp);
                              }
                        } catch (IOException e) {
                              e.printStackTrace();
                        }
                  }
            }
      }

      /**
       * 监听坦克死亡的UDP线程
       */
      private class TankDeadUDPThread implements Runnable{
            byte[] buf = new byte[300];
            @Override
            public void run() {
                  DatagramSocket ds = null;
                  try{
                        ds = new DatagramSocket(TANK_DEAD_UDP_PORT);
                  } catch (SocketException e) {
                        e.printStackTrace();
                  }
                  while(null != ds){
                        DatagramPacket dp = new DatagramPacket(buf, buf.length);
                        ByteArrayInputStream bais = null;
                        DataInputStream dis = null;
                        try{
                              ds.receive(dp);
                              bais = new ByteArrayInputStream(buf, 0, dp.getLength());
                              dis = new DataInputStream(bais);
                              int deadTankUDPPort = dis.readInt();
                              for(int i = 0; i < clients.size(); i++){
                                    Client c = clients.get(i);
                                    if(c.UDP_PORT == deadTankUDPPort){
                                          clients.remove(c);
                                    }
                              }

                        } catch (IOException e) {
                              e.printStackTrace();
                        }finally {
                              if (null != dis){
                                    try {
                                          dis.close();
                                    } catch (IOException e) {
                                          e.printStackTrace();
                                    }
                              }
                              if(null != bais){
                                    try {
                                          bais.close();
                                    } catch (IOException e) {
                                          e.printStackTrace();
                                    }
                              }
                        }
                  }
            }
      }

      public class Client{
            String IP;
            int UDP_PORT;
            int id;

            public Client(String ipAddr, int UDP_PORT, int id) {
                  this.IP = ipAddr;
                  this.UDP_PORT = UDP_PORT;
                  this.id = id;
            }
      }

      /************** 服务器可视化 **************/
//    @Override
//    public void paint(Graphics g) {
//        g.drawString("TankClient :", 30, 50);
//        int y = 80;
//        for(int i = 0; i < clients.size(); i++){//显示出每个客户端的信息
//            Client c = clients.get(i);
//            g.drawString("id : " + c.id + " - IP : " + c.IP, 30, y);
//            y += 30;
//        }
//    }
//
//    @Override
//    public void update(Graphics g) {
//        if(offScreenImage == null) {
//            offScreenImage = this.createImage(SERVER_WIDTH, SERVER_HEIGHT);
//        }
//        Graphics gOffScreen = offScreenImage.getGraphics();
//        Color c = gOffScreen.getColor();
//        gOffScreen.setColor(Color.yellow);
//        gOffScreen.fillRect(0, 0, SERVER_WIDTH, SERVER_HEIGHT);
//        gOffScreen.setColor(c);
//        paint(gOffScreen);
//        g.drawImage(offScreenImage, 0, 0, null);
//    }
//
//    public void launchFrame() {
//        this.setLocation(200, 100);
//        this.setSize(SERVER_WIDTH, SERVER_HEIGHT);
//        this.setTitle("TankServer");
//        this.addWindowListener(new WindowAdapter() {
//            @Override
//            public void windowClosing(WindowEvent e) {
//                System.exit(0);
//            }
//        });
//        this.setResizable(false);
//        this.setBackground(Color.yellow);
//        this.setVisible(true);
//        new Thread(new PaintThread()).start();
//
//    }
//
//    /**
//     * 重画线程
//     */
//    class PaintThread implements Runnable {
//        public void run() {
//            while(true) {
//                repaint();
//                try {
//                    Thread.sleep(50);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//            }
//        }
//    }
}
